#pragma once

#include <iostream>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include "../../jsonxx/json.hpp"

using namespace jsonxx;
using std::string;
using std::unordered_map;
using std::unordered_set;

class ASTConfig {
public:
    unordered_set<string> ignoredTerminals;
    unordered_set<string> childToSibling;
    unordered_map<string, string> generalization;
    unordered_set<string> compressExclusion;
    unordered_map<string, string> terminalNameMap;
    unordered_set<string> childToFields;
    unordered_set<string> mergeChilds;
    /**
     * Factory method to build ASTConfig from input stream
     * @param fin input stream
     * @return ASTConfig created from the json config
     */ 
    static ASTConfig configWithJson(std::istream& fin){
        ASTConfig config;
        json jd;
        fin >> jd;
        auto &&ignore = jd["ignoredTerminals"].as_array();
        config.ignoredTerminals = {ignore.begin(), ignore.end()};

        auto &&c2f = jd["childToFields"].as_array();
        config.childToFields = {c2f.begin(), c2f.end()};

        auto &&c2s = jd["childToSiblings"].as_array();
        config.childToSibling = {c2s.begin(), c2s.end()};

        auto &&mc = jd["mergeChilds"].as_array();
        config.mergeChilds = {mc.begin(), mc.end()};

        auto &&nameMap = jd["terminalNamesMapping"];
        for (auto iter = nameMap.begin(); iter != nameMap.end(); iter++) {
            for (auto terminal = iter.value().begin(); terminal != iter.value().end();
                 ++terminal) {
                config.terminalNameMap.insert({terminal.value().as_string(), iter.key()});
            }
        }

        auto &&rules = jd["parseTreeToASTRules"].as_array();
        for (auto i : rules) {
            if (i["type"] == "Generalization") {
                auto targets = i["targets"];
                for (auto j : targets) {
                    config.generalization.insert(
                        {j.as_string(), i["category"].as_string()});
                }
                if (i.count("compressExclusions")) {
                    config.compressExclusion = {
                        i["compressExclusions"].as_array().begin(),
                        i["compressExclusions"].as_array().end()};
                }
            }
        }
        std::cout << "Initialized AST static fields\n";
        return config;
    }
};


